﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="EditRuleDialog.cs" company="YellowFish">
//   Copyright © YellowFish 2009
// </copyright>
// <summary>
//   Describes and manipulates the edit rule dialog.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace MobilePal.Dialogs
{
  #region Imported Namespaces


  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Drawing;
  using System.Linq;
  using System.Windows.Forms;

  using Collections;

  using Controls;

  using Rules;

  using State;


  #endregion


  /// <summary>
  /// Describes and manipulates the edit rule dialog.
  /// </summary>
  public partial class EditRuleDialog: Form
  {
    #region Constants and Fields


    private readonly ActivityCollection _activityCollection;
    private readonly ActivityCategoryCollection _categoryCollection;

    private readonly ActivityCollection _ruleActivityCollection = new ActivityCollection();
    private readonly ActivityCategoryCollection _ruleCategoryCollection = new ActivityCategoryCollection();
    private readonly ActivityCollection _ruleExcludedActivityCollection = new ActivityCollection();
    private readonly ActivityCategoryCollection _ruleExcludedCategoryCollection = new ActivityCategoryCollection();
    private ActivityRule _rule;
    private Dictionary<Type, RuleSettingsBase> _settingsControls;


    #endregion


    #region Constructors and Destructors


    /// <summary>
    /// Initializes a new instance of the <see cref="EditRuleDialog"/> class.
    /// </summary>
    /// <param name="rule">
    /// The rule.
    /// </param>
    /// <param name="activityCollection">
    /// The activity collection.
    /// </param>
    /// <param name="categoryCollection">
    /// The category collection.
    /// </param>
    public EditRuleDialog(ActivityRule rule, ActivityCollection activityCollection, 
                          ActivityCategoryCollection categoryCollection)
    {
      _rule = rule;
      _activityCollection = activityCollection;
      _categoryCollection = categoryCollection;

      InitializeComponent();

      List<ActivityRuleClassInfo> classInfos = Program.GetRuleClassInfos();

      CreateRuleSettingsControls();

      typeComboBox.DisplayMember = "DisplayName";

      foreach (ActivityRuleClassInfo classInfo in classInfos)
      {
        typeComboBox.Items.Add(classInfo);
      }

      if (_rule != null)
      {
        _ruleActivityCollection.AddRange(_rule.Activities);
        _ruleCategoryCollection.AddRange(_rule.Categories);
        _ruleExcludedActivityCollection.AddRange(_rule.ExcludedActivities);
        _ruleExcludedCategoryCollection.AddRange(_rule.ExcludedCategories);

        typeComboBox.Enabled = false;
        typeComboBox.SelectedItem = classInfos.First(ruleClassInfo => ruleClassInfo.Type == _rule.GetType());
      }
      else
      {
        UpdateSettingsTab();
      }

      BuildListView(activitiesListView, _ruleActivityCollection);
      BuildListView(excludedActivitiesListView, _ruleExcludedActivityCollection);

      BuildListView(categoriesListView, _ruleCategoryCollection);
      BuildListView(excludedCategoriesListView, _ruleExcludedCategoryCollection);
    }


    #endregion


    #region Properties


    /// <summary>
    /// Gets the rule.
    /// </summary>
    /// <value>
    /// The rule.
    /// </value>
    public ActivityRule Rule
    {
      get
      {
        return _rule;
      }
    }


    #endregion


    #region Methods


    /// <summary>
    /// Raises the <see cref="Form.Closing"/> event.
    /// </summary>
    /// <param name="e">
    /// The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.
    /// </param>
    protected override void OnClosing(CancelEventArgs e)
    {
      if (DialogResult == DialogResult.Cancel)
      {
        return;
      }

      var ruleClassInfo = (ActivityRuleClassInfo)typeComboBox.SelectedItem;
      RuleSettingsBase settingsControl = null;

      if (string.IsNullOrEmpty(nameTextBox.Text))
      {
        MessageBox.Show("Invalid rule name.", "Invalid Name", MessageBoxButtons.OK, MessageBoxIcon.Hand, 
                        MessageBoxDefaultButton.Button1);

        e.Cancel = true;
      }

      if (ruleClassInfo == null)
      {
        MessageBox.Show("Please select rule type.", "Invalid Type", MessageBoxButtons.OK, MessageBoxIcon.Hand, 
                        MessageBoxDefaultButton.Button1);

        e.Cancel = true;
      }
      else
      {
        if (_settingsControls.ContainsKey(ruleClassInfo.Type))
        {
          settingsControl = _settingsControls[ruleClassInfo.Type];
        }
      }

      if (settingsControl != null)
      {
        e.Cancel = settingsControl.ValidateSettings();
      }

      if (!_ruleActivityCollection.Any() && !_ruleCategoryCollection.Any())
      {
        MessageBox.Show("Please select activities and/or categories for the rule.", "Error", MessageBoxButtons.OK, 
                        MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);

        e.Cancel = true;
      }

      if (e.Cancel)
      {
        return;
      }

      if (_rule == null)
      {
        _rule = ruleClassInfo.CreateRuleInstance();
      }

      _rule.Activities.Clear();
      _rule.Activities.AddRange(_ruleActivityCollection);

      _rule.ExcludedActivities.Clear();
      _rule.ExcludedActivities.AddRange(_ruleExcludedActivityCollection);

      _rule.Categories.Clear();
      _rule.Categories.AddRange(_ruleCategoryCollection);

      _rule.ExcludedCategories.Clear();
      _rule.ExcludedCategories.AddRange(_ruleExcludedCategoryCollection);

      if (settingsControl != null)
      {
        settingsControl.SetSettings(_rule);
      }

      _rule.Name = nameTextBox.Text;
    }


    private static void BuildListView(ListView listView, IEnumerable<Activity> collection)
    {
      var list = new List<string>();

      foreach (Activity activity in collection)
      {
        list.Add(activity.Name);
      }

      list.Sort((name1, name2) => string.Compare(name1, name2));

      BuildListView(listView, list);
    }


    private static void BuildListView(ListView listView, IEnumerable<ActivityCategory> collection)
    {
      var list = new List<string>();

      foreach (ActivityCategory activityCategory in collection)
      {
        list.Add(activityCategory.Name);
      }

      list.Sort((name1, name2) => string.Compare(name1, name2));

      BuildListView(listView, list);
    }


    private static void BuildListView(ListView listView, IEnumerable<string> collection)
    {
      listView.BeginUpdate();
      listView.Items.Clear();

      foreach (string item in collection)
      {
        var listViewItem = new ListViewItem(item);
        listView.Items.Add(listViewItem);
      }

      foreach (ColumnHeader header in listView.Columns)
      {
        header.Width = -1;
      }

      listView.EndUpdate();
    }


    private void AddSettingsTab()
    {
      tabControl.SuspendLayout();
      tabControl.Controls.Add(settingsTabPage);
      tabControl.ResumeLayout(true);
    }


    private void CancelMenuItemClick(object sender, EventArgs e)
    {
      DialogResult = DialogResult.Cancel;
    }


    private void CreateRuleSettingsControls()
    {
      List<ActivityRuleSettingsControlClassInfo> classInfos = Program.GetActivityRuleSettingsControlsClassInfos();

      _settingsControls = new Dictionary<Type, RuleSettingsBase>();

      foreach (ActivityRuleSettingsControlClassInfo settingsControlClassInfo in classInfos)
      {
        RuleSettingsBase ruleSettingsControl = null;

        try
        {
          ruleSettingsControl = settingsControlClassInfo.CreateControlInstance();
        }
        catch
        {
          MessageBox.Show("An error occurred loading rule settings control.", "Error", MessageBoxButtons.OK, 
                          MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
        }

        if (ruleSettingsControl == null)
        {
          continue;
        }

        _settingsControls.Add(settingsControlClassInfo.RuleType, ruleSettingsControl);
        ruleSettingsControl.Visible = false;
        ruleSettingsControl.Location = new Point(4, 4);
        ruleSettingsControl.Size = new Size(Width - 8, Height - 8);
        ruleSettingsControl.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;

        settingsTabPage.Controls.Add(ruleSettingsControl);

        if (_rule != null && settingsControlClassInfo.RuleType == _rule.GetType())
        {
          ruleSettingsControl.GetSettings(_rule);
        }
      }
    }


    private void EditActivitiesButtonClick(object sender, EventArgs e)
    {
      EditActivitiesList(activitiesListView, _ruleActivityCollection);
    }


    private void EditActivitiesList(ListView listView, ObservableCollection<Activity> activityCollection)
    {
      var dialog = new ActivitiesListDialog(_activityCollection, _categoryCollection);

      dialog.SelectedItems = new List<object>(activityCollection.Cast<object>());
      dialog.ShowCheckBoxes = true;

      DialogResult result = dialog.ShowDialog();

      if (result != DialogResult.OK)
      {
        return;
      }

      activityCollection.Clear();
      activityCollection.AddRange(dialog.SelectedItems.Cast<Activity>());

      BuildListView(listView, activityCollection);
    }


    private void EditCategoriesButtonClick(object sender, EventArgs e)
    {
      EditCategoriesList(categoriesListView, _ruleCategoryCollection);
    }


    private void EditCategoriesList(ListView listView, ObservableCollection<ActivityCategory> categories)
    {
      var dialog = new CategoriesListDialog(_categoryCollection);

      dialog.SelectedItems = new List<object>(categories.Cast<object>());
      dialog.ShowCheckBoxes = true;

      DialogResult result = dialog.ShowDialog();

      if (result != DialogResult.OK)
      {
        return;
      }

      categories.Clear();
      categories.AddRange(dialog.SelectedItems.Cast<ActivityCategory>());

      BuildListView(listView, categories);
    }


    private void EditExcludedActivitiesButtonClick(object sender, EventArgs e)
    {
      EditActivitiesList(excludedActivitiesListView, _ruleExcludedActivityCollection);
    }


    private void EditExcludedCategoriesButtonClick(object sender, EventArgs e)
    {
      EditCategoriesList(excludedCategoriesListView, _ruleExcludedCategoryCollection);
    }


    private void OkMenuItemClick(object sender, EventArgs e)
    {
      DialogResult = DialogResult.OK;
    }


    private void RemoveSettingsTab()
    {
      if (!tabControl.Controls.Contains(settingsTabPage))
      {
        return;
      }

      tabControl.SuspendLayout();
      tabControl.Controls.Remove(settingsTabPage);
      tabControl.SelectedIndex = 0;
      tabControl.ResumeLayout(true);
    }


    private void TypeComboBoxSelectedIndexChanged(object sender, EventArgs e)
    {
      UpdateSettingsTab();
    }


    private void UpdateSettingsTab()
    {
      var classInfo = (ApplicationClassInfo)typeComboBox.SelectedItem;

      RemoveSettingsTab();

      foreach (KeyValuePair<Type, RuleSettingsBase> keyValuePair in _settingsControls)
      {
        if (keyValuePair.Key == classInfo.Type)
        {
          keyValuePair.Value.Visible = true;
          AddSettingsTab();
        }
        else
        {
          keyValuePair.Value.Visible = false;
        }
      }
    }


    #endregion
  }
}